#include<iostream>
#include<unistd.h>
#include<cstdio>
#include<cstdlib>
#include <ctype.h>
#include<cstring>
#include<unistd.h>
//#include<sys/type.h>
#include<sys/wait.h>
#include<ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

using namespace std;


//命令行参数表
#define MAXARGC 128
char* g_argv[MAXARGC];
int g_argc =0;

//重定向定义
#define NONE_REDIR 0
#define INPUT_REDIR 1
#define OUTPUT_REDIR 2
#define APPEND_REDIR 3
int redir=NONE_REDIR;
std::string filename;


//当前目录
char cwd[1024];
char cwdenv[1024];

//环境变量
#define MAX_ENVS 300
char* g_env[MAX_ENVS];
int g_envs=0;


#define COMMAND_SIZE 1024
#define FORMAT "[%s@%s %s]#"
//获得用户名
const char* GetUserName()
{
  const char* name= getenv("USER");
    return name==nullptr?"None":name;
}


//获得主机名
const char* GetHostName()
{
  const char* hostname= getenv("HOSTNAME");
    return hostname==nullptr?"None":hostname;
}
//获取家目录
const char* GetHome()
{
  const char* home=getenv("HOME");
  return home==nullptr?"None":home;
}
//获得当前目录
const char* GetPwd()
{
   // const char* pwd= getenv("PWD");
   // return pwd==nullptr?"None":pwd;
   const char* pwd=getcwd(cwd,sizeof(cwd));
   if(pwd!=nullptr)
   {
     snprintf(cwdenv,sizeof(cwdenv),"PWD=%s",pwd);
     putenv(cwdenv);
   }
   return getenv("PWD");
}
std::string DirName(const char* pwd)
{
#define SLASH "/"
  std::string dir=pwd;
  auto pos=dir.rfind(SLASH);
  if(pos==std::string::npos) return "BUGS";
  return dir.substr(pos+1);
}

//制作命令行提示符
void MakeCommandPrompt(char* cmd_prompt,size_t size)
{
  snprintf(cmd_prompt,size,FORMAT,GetUserName(),GetHostName(),DirName(GetPwd()).c_str());
//  snprintf(cmd_prompt,size,FORMAT,GetUserName(),GetHostName(),GetPwd());
}
//输出命令行提示符
void  PrintCommandPrompt()
{
  char cmd_prompt[COMMAND_SIZE];
  MakeCommandPrompt(cmd_prompt,COMMAND_SIZE);
  printf("%s",cmd_prompt);
  fflush(stdout);
}
//获取用户输入的命令行
bool GetCommandLine(char* cmd_line,int size)
{
  //ls -l -a -> "ls -l -a/n"
 char* c= fgets(cmd_line,size,stdin);
  if(c==nullptr) return false;
  //在输入命令行时，最后一下会回车一一下，所以最后一个字符是/n，这一步是为了清理/n
  cmd_line[strlen(cmd_line)-1]=0;
  if(strlen(cmd_line)==0) return false;
  return true;
}

     //分析用户命令“ls -l -a”->"ls""-l""-a"
  bool CommandParse(char* com_line)
{
   #define SEP " "
  g_argc=0;
  g_argv[g_argc++]=strtok(com_line,SEP);
  while((bool)(g_argv[g_argc++]=strtok(nullptr,SEP)));
  g_argc--;
  return true;
}
//初始化环境变量
void InitEnv()
{
  extern char** environ;
  memset(g_env,0,sizeof(g_env));
  g_envs=0;
  //获取环境变量
  for(int i=0;environ[i]!=nullptr;i++)
  {
    //申请空间
    g_env[i]=(char*)malloc(strlen(environ[i])+1);
    strcpy(g_env[i],environ[i]);
    g_envs++;
  }
  g_env[g_envs++]=(char*)("haha==lalalalal");
  g_env[g_envs]=nullptr;
  //导成环境变量
  for(int i=0;g_env[i]!=nullptr;i++)
  {
    putenv(g_env[i]);
  }//判断内建命令并处y
    environ=g_env;
}
//cd命令实现
bool Cd()
{
  if(g_argc==1)
  {
    std::string  home=GetHome();
    if(home.empty()) return true;
    chdir(home.c_str());
   // cout<<"cd我的pid"<<getpid()<<endl;
  }
  else
  {
    std::string where=g_argv[1];
      if(where=="-")
      {
        ;
      }
    else if(where=="~")
    {
       ;
    }
    else 
    {
      chdir(where.c_str());
    }
  }
  return true;
}
//判断内建命令并执行
bool CheckAndExecBuiltin()
{
  std::string cmd=g_argv[0];
  if(cmd=="cd")
  {
    Cd();
    return true;
  }
return false;
}



  int Execute()
{
  pid_t id=fork();
  if(id==0)
  {
    
    
      if(redir==APPEND_REDIR)
      {
        int fd=open(filename.c_str(),O_CREAT|O_APPEND|O_WRONLY,0666);
        if(fd<0) exit(1);
        dup2(fd,1);
        close(fd);
      } 
      else if(redir==OUTPUT_REDIR)
      {
        int fd=open(filename.c_str(),O_CREAT|O_TRUNC|O_WRONLY,0666);
        if(fd<0) exit(1);
        dup2(fd,1);
        close(fd);
      }
      else if(redir==INPUT_REDIR)
      {
        int fd=open(filename.c_str(),O_RDONLY);
        if(fd<0) exit(1);
        dup2(fd,0);
        close(fd);
      }
      
    //child
    execvp(g_argv[0],g_argv);
    exit(1);
  }
  //father
  pid_t rid=waitpid(id,nullptr,0);
  (void)rid;
  return 0;

}
void  TrimSpace(char* cmd_line,int & end)
{
  while(isspace(cmd_line[end]))
    end++;
}
void RedirCheck(char* cmd_line)
{
  redir=0;
  filename.clear();
  int begin=0,end=strlen(cmd_line)-1;
  while(end!=begin)
  {
    if(cmd_line[end]=='<')
    {
    cmd_line[end++]=0;
    TrimSpace(cmd_line,end);
    redir=INPUT_REDIR;
    filename=cmd_line+end;
    break;
    }
   else if(cmd_line[end]=='>')
    {
      if(cmd_line[end-1]=='>') 
      redir=APPEND_REDIR;
      else
    redir=OUTPUT_REDIR;

    cmd_line[end++]=0;
    TrimSpace(cmd_line,end);
    filename=cmd_line+end;
    break;
    }
   else
   {
     end--;
   }
  }
}




int main()
{
  
  //  InitEnv();
 while(1)
 {
     //输出命令行提示符
     PrintCommandPrompt();
     //获取用户输入的命令行
     char com_line[COMMAND_SIZE];
     if(!GetCommandLine(com_line,COMMAND_SIZE))
     continue;

     //分析用户命令“ls -l -a”->"ls""-l""-a"
     CommandParse(com_line);
    //检查重定向
    RedirCheck(com_line);

     if( CheckAndExecBuiltin())
       continue;

    //执行替换命令
    Execute();

 }
  return 0;
}

